`include "definitions.sv"

module NewLabel_memif
(
	input logic m_rstn,
	input logic mclk,

	//outer
	//output logic		mclk_o,
	input  logic [23:0]	data_i,
	output logic [23:0]	data_o,
	output logic 		oe_m,
	output logic [25:0]	addr_o,
	output logic 		cs_o,
	output logic [2:0]	gpctrl_o,

	//inner
	input  logic [47:0]	data_i_m,
	output logic [47:0]	data_o_m,
	
	output  logic 		wr_valid,
	input logic		wr_full,
	output  logic 		rd_valid,
	input logic		rd_empty,
	
	output logic	err_memif,
	input logic	finish_int
);

logic wr_mem_1;
logic wr_mem_2;
logic ld_data_mem;

logic data_mem_valid;
logic data_mem_valid_pre;
always_ff @(posedge mclk)
begin
	data_mem_valid_pre <= ld_data_mem;
	data_mem_valid <= data_mem_valid_pre;
end

always_ff @(posedge mclk or negedge m_rstn)
begin
	unique if(!m_rstn)
		addr_o <= '0;
	else if(wr_mem_1|wr_mem_2)
		addr_o <= addr_o + 1'b1;
	//else if(data_mem_valid)
	else if(data_mem_valid_pre)
		addr_o <= addr_o - 1'b1;
	else
		addr_o <= addr_o;
end

always_ff @(posedge mclk or negedge m_rstn)
begin
	unique if(!m_rstn)
		data_o <= '0;
	else if(wr_mem_1)
		data_o <= data_i_m[23:0];
	else if(wr_mem_2)
		data_o <= data_i_m[47:24];
	else
		data_o <= data_o;
end

logic [23:0]	data;
logic ld_data;
always_ff @(posedge mclk or negedge m_rstn)
begin
	unique if(!m_rstn)
		data <= '0;
	else if(ld_data)
		data <= data_i;
	else
		data <= data;
end

/*always_ff @(posedge mclk or negedge m_rstn)
begin
	unique if(!m_rstn)
		data_o_m <= '0;
	else if(data_mem_valid & (!addr_o[0]))
		data_o_m <= {data, data_i};
	else
		data_o_m <= data_o_m;
end*/

always_comb
begin
	unique if(!m_rstn)
		data_o_m = '0;
	else if(data_mem_valid_pre & (!addr_o[0]))
		data_o_m = {data, data_i};
	else
		data_o_m = data_o_m;
end

/*logic [8:0]	burst_count;
always_ff @(posedge mclk or negedge m_rstn)
begin
	if(!m_rstn)
		burst_count <= '0;
	else if(burst_count == 'hff)
		burst_count <= '0;
	else if(data_mem_valid)
		burst_count <= burst_count + 1'b1;
end
logic data_burst_over;
assign data_burst_over = (burst_count == 'hff)? 1:0;*/

logic img_data_over;
assign img_data_over = (addr_o == 0)? 1:0;

always_ff @(posedge mclk or negedge m_rstn)
begin
	unique if(!m_rstn)
	begin
		oe_m <= 1'b0;
		cs_o <= 1'b0;
		gpctrl_o <= '0;
	end
	else if(wr_mem_1|wr_mem_2)
	begin
		oe_m <= 1'b1;
		cs_o <= 1'b1;
		gpctrl_o <= 'h1;
	end
	else if(ld_data_mem)
	begin
		oe_m <= 1'b0;
		cs_o <= 1'b1;
		gpctrl_o <= 'h2;
	end
	else
	begin
		oe_m <= 1'b0;
		cs_o <= 1'b0;
		gpctrl_o <= 'h0;
	end
end

logic wr_valid_pre;
//////////////////////////////// MemIf State Machine(MI) Logic ////////////////////////
// Used for control memIf work!

enum {IDLE_MI, PS1_pre, PS1, PS1_post, PS2_pre, PS2_pre2, PS2, PS2_post, PS2_post2} state_MI, next_state_MI;

always_ff @(posedge mclk, negedge m_rstn)
begin
	if(!m_rstn)
		state_MI <= IDLE_MI;
	else
		state_MI <= next_state_MI;
end

always_comb
begin
	next_state_MI = state_MI;
	rd_valid = 1'b0;
	wr_valid_pre = 1'b0;
	ld_data_mem = 1'b0;
	ld_data = 1'b0;
	wr_mem_1 = 1'b0;
	wr_mem_2 = 1'b0;

	case(state_MI)
		IDLE_MI:
		begin
			if(!rd_empty)
			begin
				//rd_valid = 1'b1;	//for the first wrong item "0"
				next_state_MI = PS1_pre;
			end
			else
			begin
				next_state_MI = IDLE_MI;
			end
		end
		PS1_pre:
		begin
			if(!rd_empty)
			begin
				rd_valid = 1'b1;
				next_state_MI = PS1;
			end
			else if(finish_int)
			begin
				next_state_MI = PS2_pre;
			end
		end
		PS1:
		begin
			wr_mem_1 = 1'b1;
			next_state_MI = PS1_post;
		end
		PS1_post:
		begin
			wr_mem_2 = 1'b1;
			if(!rd_empty)
			begin
				rd_valid = 1'b1;
				next_state_MI = PS1;
			end
			else
			begin
				rd_valid = 1'b0;
				next_state_MI = PS1_pre;
			end
		end

		PS2_pre:
		begin
			ld_data_mem = 1'b1;
			next_state_MI = PS2_pre2;
		end
		PS2_pre2:
		begin
			ld_data_mem = 1'b1;
			next_state_MI = PS2;
		end
		PS2:
		begin
			ld_data = 1'b1;
			if(!wr_full/* & data_mem_valid*/)
			begin
				wr_valid_pre = 1'b1;
				ld_data_mem = 1'b1;
				next_state_MI = PS2_post;
			end
			else
			begin
				ld_data_mem = 1'b0;
				next_state_MI = PS2_post2;
			end
		end
		PS2_post:
		begin
			ld_data_mem = 1'b1;
			next_state_MI = PS2;
			if(img_data_over)
			begin
				ld_data_mem = 1'b0;
				next_state_MI = IDLE_MI;
			end
		end
		PS2_post2:
		begin
			if(img_data_over)
			begin
				//ld_data_mem = 1'b0;
				next_state_MI = IDLE_MI;
			end
			else if(!wr_full)
			begin
				ld_data_mem = 1'b1;
				if(!addr_o[0])
					wr_valid_pre = 1'b1;
				next_state_MI = PS2_pre2;
			end
		end

// synopsys translate_off
		default:
		begin
			next_state_MI = IDLE_MI;
			$display("TOP LEVEL SM: Entered non existing state : %b (%t)", state_MI, $time);
		end
// synopsys translate_on
	endcase
end

always_ff @(posedge mclk)
	wr_valid <= wr_valid_pre;


endmodule
